package orxatas.travelme.manager;

import java.util.ArrayList;

import orxatas.travelme.manager.exceptions.GroupNameInvalid;
import orxatas.travelme.sync.SyncGroups;

import orxatas.travelme.activity.AsyncActivity;
import orxatas.travelme.entity.Comment;
import orxatas.travelme.entity.Group;
import orxatas.travelme.sync.SyncData.SyncDataType;
import orxatas.travelme.sync.exceptions.ImposibleAcceptInvitation;
import orxatas.travelme.sync.exceptions.ImposibleRemoveFriendFrom;

/**
 * Gestor de grupos
 * Modulo encargado de relizar las peticiones relacionadas con otros grupos.
 * */
public class GroupManager {
	
	/**
	 * Actividad actual.
	 * */
	private AsyncActivity asyncActivity;

	/**
	 * Lista de grupos.
	 * */
	static private ArrayList<Group> groupList;
	
	/**
	 * DAO de los grupos 
	 */
	private SyncGroups sync;
	
	int tamMinName = 3;
	int tamMaxName = 49;
	
	/**
	* Constructor
	* */
	public GroupManager(AsyncActivity asyncActivity){
		
		this.asyncActivity = asyncActivity;
		sync = new SyncGroups(this, asyncActivity);

		groupList = sync.getGroups();
		if(groupList == null) 
			groupList = new ArrayList<Group>();
	}
	
	/**
	 * Envia una petición para crear un nuevo grupo.
	 * @param {Group} group Instancia de grupo a añadir.
	 * */
	public Group addNewGroup(String groupName) throws GroupNameInvalid{
		if(nameIsValid(groupName)){
			Group newGroup = null;
			newGroup = sync.createGroup(groupName);
			
			if(newGroup!=null)
				groupList.add(newGroup);
			return newGroup;
		}
		else throw new GroupNameInvalid();
	}
	
	/**
	 * Obtiene el listado completo de grupos.
	 * @return Lista completa de grupos.
	 * */
	public ArrayList<Group> getGroupList(){
		groupList = sync.getGroups();
		
		return groupList;
	}
	
	/**
	 * Obtiene un grupo en concreto.
	 * @param {int} idGroup Identificador del grupo que se desea obtener.
	 * @return El grupo solicitado o null si el grupo no existe.
	 * */	
	public Group getGroup(int idGroup){
		/*Group group = findGroup(idGroup);
		if(group != null)
			return group;*/ //TODO Tiene que estar "nuevo" de la base de datos.
		groupList = sync.getGroups();
		
		return findGroup(idGroup);
	}
	
	/**
	 * Synchronize data information.
	 * 
	 * @param nextData An optional next data to sync. Put it as a null.
	 * */
	public void synchronize(SyncDataType nextData){
		sync.synchronize(nextData);
	}
	
	/**
	 * Añade un comentario a un grupo.
	 * 
	 * @param idGroup Identificador del grupo donde va el comentario.
	 * @param commentText Texto del comentario.
	 * */
	public Comment addCommentTo(int idGroup, String commentText){

		Group g = findGroup(idGroup);
		if(g != null){
			Comment newComment = null;
			newComment = sync.addCommentTo(idGroup, commentText);
			
			if(newComment != null){	
				insertComment(g, newComment);
				return newComment;
			}	
		}
		return null;
	}
	
	/**
	 * Añade un comentario con relación de un lugar en un grupo.
	 * 
	 * @param idGroup Identificador del grupo donde va el comentario.
	 * @param commentText Texto del comentario.
	 * @param idPlace Lugar al que hace referencia el comentario.
	 * */
	public Comment addCommentWithPlaceTo(int idGroup, String commentText, int idPlace){
		
		Group g = findGroup(idGroup);
		if(g != null){
			Comment newComment = null;
			newComment = sync.addCommentTo(idGroup, commentText, idPlace);
			
			if(newComment != null){	
				insertComment(g, newComment);
				return newComment;
			}	
		}
		return null;
	}
	
	/**
	 * Invita un usuario al grupo (sólo puede hacerlo el admin del grupo).
	 * */
	public void inviteUserTo(int idGroup, int idFriend){
		
				
		sync.addFriendTo(idGroup, idFriend);
	}
	
	/**
	 * Acepta la invitacion de acceso al grupo.
	 * 
	 * @param idGroup identificado del grupo aceptado
	 * @throws ImposibleAcceptInvitation 
	 * */
	public void acceptInvitation(int idGroup ) throws ImposibleAcceptInvitation{
		
		sync.acceptInvitation(idGroup);
	}
	
	/**
	 * Rechaza la invitacion de acceso al grupo. El administrador no puede rechazar el grupo, deberia eliminarlo
	 * 
	 * @param idGroup identificado del grupo rechazado
	 */
	public void rejectInvitation(int idGroup ){
		
		sync.rejectInvitation(idGroup); 
	}
	
	/***
	 * Cambia el nombre de un grupo, solo es posible para el propietario del grupo
	 * 
	 * @param idGroup el identificador del grupo
	 * @param newName el nuevo nombre para poner
	 * @throws GroupNameInvalid 
	 */
	public void renameGroup(int idGroup, String newName) throws GroupNameInvalid{
		if(nameIsValid(newName)){
			Group p = findGroup(idGroup);
			p.setName(newName);
		}
		else
			throw new GroupNameInvalid();
		
	}
	
	/***
	 * A�ade un lugar al grupo 
	 * 
	 * @param idGroup el identificador del grupo
	 * @param place el lugar a a�adir
	 */
	
	public void addPlaceToGroup(int idGroup, int idPlace){
		
		sync.addPlaceTo(idGroup, idPlace);
	}
	
	/***
	 * Elimina un lugar de la lista de un grupo concreto, solo para el propietario
	 * 
	 * @param idGroup el identificador del grupo
	 * @param place el lugar para eliminar
	 */
	public void removePlaceOfGroup(int idGroup, int idPlace){
		
		sync.removePlaceOf(idGroup, idPlace);
	}
	
	/**
	 * Elimina a un amigo de la lista de los participantes del grupo, solo para el propietario
	 * 
	 * @param idGroup el identificador del grupo 
	 * @param idUser el identificador del amigo eliminado
	 * @throws ImposibleRemoveFriendFrom 
	 */
	public void removeFriendOfGroup(int idGroup, int idUser) throws ImposibleRemoveFriendFrom{
		
		sync.removeFriendOf(idGroup, idUser);
	}
	
	
	
	private Group findGroup(int idGroup){
		for(Group g: groupList)
			if(g.getIdOffline()==idGroup){
				return g;
			}
		return null;
	}
	
	private void insertComment(Group group, Comment comment){
		
		ArrayList<Comment> com = group.getComments();
		com.add(comment);
		group.setComments(com);
	}
	
	private Boolean nameIsValid(String name){
				
		if(name.length() < tamMinName || name.length() > tamMaxName)
			return false;		
		return true;
	}

}
